package com.github.netty.handler;

import com.github.netty.constant.Constant;
import com.github.netty.core.AbstractNettyServerHandler;
import com.github.netty.factory.ServerHandshakeFactory;
import com.github.netty.holder.NettyHolder;
import com.github.netty.properties.NettyProperties;
import com.github.netty.service.IBusinessMessageHandler;
import com.github.netty.utils.RequestParamUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.websocketx.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Component;

import java.util.Map;


/**
 * @author ArchieSean
 * @description 默认的netty服务端消息处理类
 * @date 2024-08-11
 */

@Component
@ChannelHandler.Sharable
public class DefaultNettyServerHandler extends AbstractNettyServerHandler {

    private static final Log logger = LogFactory.getLog(DefaultNettyServerHandler.class);

    /**
     * 属性配置
     */
    private final NettyProperties properties;
    /**
     * 自定义的消息处理
     */

    private final IBusinessMessageHandler iBusinessHandler;

    /**
     * 握手工厂
     */
    private final WebSocketServerHandshakerFactory factory;


    /**
     * 握手对象实例
     */
    private  WebSocketServerHandshaker handshake;
    public DefaultNettyServerHandler(NettyProperties properties, IBusinessMessageHandler iBusinessHandler) {
        this.properties = properties;
        this.iBusinessHandler = iBusinessHandler;
        this.factory = ServerHandshakeFactory.getFactory(
                Constant.LINK + properties.getPort() + properties.getUrl());
    }




    /**
     * @param channel 信道
     * @param frame   套接字
     *                用于处理业务，点对点、广播
     */
    @Override
    protected void handlerService(Channel channel, WebSocketFrame frame) {
        String message = ((TextWebSocketFrame) frame).text();
        iBusinessHandler.handler(channel, message);
    }

    /**
     * 关闭握手
     *
     * @param ctx   ctx
     * @param frame frame
     */
    @Override
    public void stopHandShaker(ChannelHandlerContext ctx, WebSocketFrame frame) {
        handshake.close(ctx.channel(), ((CloseWebSocketFrame) frame).retain());
    }

    /**
     * 用于实例化握手对象
     *
     * @param request request
     */
    @Override
    public void newHandshake(FullHttpRequest request) {
        handshake= factory.newHandshaker(request);
    }

    @Override
    public WebSocketServerHandshaker getHandshake() {
        return handshake;
    }

    /**
     * 用于处理握手逻辑
     *
     * @param ctx       ctx
     * @param request   request
     */
    @Override
    public void handlerHandshake(ChannelHandlerContext ctx, FullHttpRequest request) {
        //从连接请求中获取请求参数
        Map<String, String> params = RequestParamUtil.urlSplit(request.uri());
        String paramValue = params.get(NettyHolder.CACHE_KEY);
        Channel channel = ctx.channel();

        //设置信道自定义参数
        channel.attr(NettyHolder.ATTR_CACHE_KEY).set(paramValue);

        //缓存信道
        NettyHolder.CHANNELS.add(channel);
        //开启点对点时，缓存channel
        if (properties.isPoint2point()) {
            NettyHolder.CHANNEL_MAP.put(paramValue, channel);
        }
        handshake.handshake(channel, request);
        logger.info("握手成功，客户端请求uri:" + request.uri() + "建立连接成功！");
    }

    /**
     * netty消息处理方法
     *
     * @param ctx ctx
     * @param o   消息内容
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object o) {
        if (o instanceof FullHttpRequest) {
            FullHttpRequest fullHttpRequest = (FullHttpRequest) o;
            handHttpRequest(ctx, fullHttpRequest);
        } else if (o instanceof WebSocketFrame) {
            WebSocketFrame socketFrame = (WebSocketFrame) o;
            handWebsocketFrame(ctx, socketFrame);
        }

    }

    /**
     * 断开连接
     *
     * @param ctx ctx
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        clearSession(ctx.channel());
        logger.info("客户端：" + ctx.channel().id().asLongText() + " 断开连接");


    }


    /**
     * 有客户端连接时触发
     *
     * @param ctx ctx
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        logger.info("有客户端：" + ctx.channel().id().asLongText() + " 连接");
    }

    /**
     * 发生异常时触发
     *
     * @param ctx   ctx
     * @param cause 原因
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        logger.error("出现异常：", cause);
        ctx.close();
    }

    /**
     * 服务端接收客户端数据结束之前调用
     *
     * @param ctx ctx
     */

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.flush();
    }
}
